#ifndef __GENERATOR_CACHE_H__
#define __GENERATOR_CACHE_H__

#pragma once

struct GENERATOR_ERROR_INFO {
   dsSTRING    command;
   dsSTRING    file;
   int         line;

   mutable dsSTRING errorMsg;
   mutable int errorsCount;

   GENERATOR_ERROR_INFO(void)
      : line(-1)
      , errorsCount(0)
   {}

   void Init(dsSTRING command, dsSTRING file, int line) { this->command = command; this->file = file; this->line = line; errorMsg.Clear(); errorsCount = 0; }
};

class GENERATOR_CALLBACK {
public:
   virtual bool Begin            (const GENERATOR_ERROR_INFO & errorInfo) { return true; };
   virtual bool Input            (const dsSTRING & params, const dsSTRING & text, const GENERATOR_ERROR_INFO & errorInfo) { return true; }
   virtual bool Output           (const dsSTRING & params, dsSTRING & res, const GENERATOR_ERROR_INFO & errorInfo)  { return true; }
   virtual bool End              (const GENERATOR_ERROR_INFO & errorInfo) { return true; };
   virtual ~GENERATOR_CALLBACK   (void) {}
};

class GENERATOR_CACHE {
public:
   enum { VERSION = 0x0001 };

   GENERATOR_CACHE(void)
      : errorsCount(0)
      , newFiles(0)
      , updatedFiles(0)
   {}

   ~GENERATOR_CACHE(void);      

   struct BLOCK_INFO_T {
      bool                 isInput;
      int                  lineBegin;
      int                  lineEnd;

      dsSTRING             generatorName;
      GENERATOR_CALLBACK * generator;
      dsSTRING             params;

      mutable dsSTRING     outputText;

      BLOCK_INFO_T(void)
         : isInput(false), lineBegin(-1), lineEnd(-1), generator(NULL)
      {}
   };

   struct FILE_INFO_T {
      INT64                time;
      INT64                newTime;
      dsVECTOR<BLOCK_INFO_T> blocks;

      FILE_INFO_T(void)
         : time(0), newTime(0)
      {}
   };

   struct GENERATOR_INFO_T {
      dsSTRING             name;
      GENERATOR_CALLBACK * callback;
   };

   void ResetExtensions    (void);
   void AddExtension       (const char * ext);
   void AddGenerator       (const dsSTRING & name, GENERATOR_CALLBACK * callback);

   void ResetErrors        (void);
   bool Search             (const char * path, const dsVECTOR<dsSTRING> & excludePath);

   void Load               (const char * filename);
   void Save               (const char * filename);

   bool Execute            (void);

   const FILE_INFO_T &     GetFileInfo(const dsSTRING & filename) const { return cache[filename]; }

private:
   void DoSearch           (const dsSTRING & path, const dsVECTOR<dsSTRING> & exclude);
   void DoProcessFile      (const dsSTRING & filename, FILE_INFO_T & info);
   dsSTRING NormalizePath  (dsSTRING path);

   bool ReadLines          (const dsSTRING & filename, dsVECTOR<dsSTRING> & lines);

   void AddErrorMsg        (const dsSTRING & file, int line, const dsSTRING & msg);

public:
   int                     errorsCount;
   dsSTRING                errorMsg;

   dsVECTOR<dsSTRING>      extensions;

   int                     newFiles;
   int                     updatedFiles;
   dsVECTOR<GENERATOR_INFO_T> gens;

   typedef std::map<dsSTRING, FILE_INFO_T> FILE_INFO_MAP_T;
   mutable FILE_INFO_MAP_T cache;
};

void genParseArgs(const dsSTRING & params, dsVECTOR<dsSTRING> & res);

#endif // __GENERATOR_CACHE_H__